package Guile::Space::Result;
use warnings;
use strict;

use Moose;

#
#   The value that was returned by the guile space execution. This is a
#   rather complex structure (mostly) as you can see by the accessor
#   methods below.
#
has 'value',
    is          => 'rw',
    ;

#
#   A reference to our parent guile space object. We need this mainly to
#   lookup containers.
#
has 'guile_space',
    is          => 'rw',
    weak_ref    => 1,
    ;

#
#   this is the mark that tells which type of exception is requested.
#
sub jump_mark       { (shift)->value->[0] }

#
#   Current possible marks are those for final values, which terminate
#   the run cycle, or horizon-jumps (or callbacks) to the perl space
#   to obtain values.
#
sub is_final        { (shift)->jump_mark eq 'perl-leave-horizon-space' }
sub is_callback     { (shift)->jump_mark eq 'perl-horizon-jump' }
sub is_exception    { (shift)->jump_mark eq 'guile-space-exception' }

sub exception_key   { (shift)->value->[1] }
sub exception_args  { (shift)->value->[2] }
sub exception_msg   { 
    my ( $self ) = @_;
    my @args = @{ $self->exception_args };
    my ( $proc, $msg, $ls ) = @args;
    return "$proc: " . Guile::call( 
        format => Guile::eval_str('#f'), $msg, ( $ls ? @$ls : ()) );
}

#
#   Returns the final value. This only makes sense when 'is_final'
#   is true.
#
sub final_value     { (shift)->value->[1] }

#
#   In case of a horizon jump, we need more options that are provided by
#   the exception.
#   + The continuation is the place where we reenter with the processed
#     return value.
#   + The type is either 'anonymous' or 'named' to specify the type of
#     value requested.
#   + Name refers to either the key of the named container, or the index
#     if it was an anonymous one.
#   + The args are simply the arguments passed to the callback lambda.
#
sub continuation    { (shift)->value->[1] }
sub _type           { (shift)->value->[2][0] }
sub _name           { (shift)->value->[2][1] }
sub _args           { (shift)->value->[2][2] }

#
#   Shortcut to obtain the container corresponding with this callback.
#
sub container {
    my ( $self ) = @_;
    return $self->guile_space->fetch_container(
        type => $self->_type,
        name => $self->_name,
    );
}

#
#   This uses the container to execute the callback. The container is
#   responsible for how to evaluate the arguments and what to return.
#
sub execute_callback {
    my ( $self ) = @_;
    my $container = $self->container;
    return $container->execute( $self->_args );
}


1;
